use super::dao::{BaseDao, UpdateDao};
use crate::db::po::{
    self,
    network_acl_rule::{ActiveModel, Column, Entity, Model},
};
use sea_orm::{ColumnTrait, DatabaseConnection};
use sea_query::IntoCondition;

#[derive(Debug, Default, Clone, Eq, PartialEq)]
pub struct Filter {
    pub network_acl_rule_id: Option<String>,
    pub network_acl_id: Option<String>,
    pub direction: Option<u32>,
    pub index: Option<u32>,
}

impl IntoCondition for Filter {
    fn into_condition(self) -> sea_query::Condition {
        let mut condition = sea_query::Condition::all();

        if let Some(network_acl_rule_id) = self.network_acl_rule_id {
            condition = condition.add(Column::NetworkAclRuleId.eq(network_acl_rule_id));
        }

        if let Some(network_acl_id) = self.network_acl_id {
            condition = condition.add(Column::NetworkAclId.eq(network_acl_id));
        }

        if let Some(direction) = self.direction {
            condition = condition.add(Column::Direction.eq(direction));
        }

        if let Some(index) = self.index {
            condition = condition.add(Column::Index.eq(index));
        }

        condition
    }
}

#[derive(Debug, Default, Clone, PartialEq)]
pub struct UpdateParams {
    pub description: po::ActiveValue<String>,
    pub protocol: po::ActiveValue<Option<u32>>,
    pub action: po::ActiveValue<u32>,
    pub src_ip_address: po::ActiveValue<po::IpAddr>,
    pub src_ip_prefix_length: po::ActiveValue<u8>,
    pub dst_ip_address: po::ActiveValue<po::IpAddr>,
    pub dst_ip_prefix_length: po::ActiveValue<u8>,
}

impl Into<ActiveModel> for UpdateParams {
    fn into(self) -> ActiveModel {
        ActiveModel {
            id: Default::default(),
            network_acl_rule_id: Default::default(),
            network_acl_id: Default::default(),
            index: Default::default(),
            description: self.description,
            protocol: self.protocol,
            direction: Default::default(),
            action: self.action,
            src_ip_address: self.src_ip_address,
            src_ip_prefix_length: self.src_ip_prefix_length,
            dst_ip_address: self.dst_ip_address,
            dst_ip_prefix_length: self.dst_ip_prefix_length,
            create_timestamp_millis: po::ActiveValue::NotSet,
            update_timestamp_millis: po::ActiveValue::NotSet,
        }
    }
}

#[async_trait::async_trait]
pub trait NetworkAclRuleDao:
    BaseDao<
        Model = Model,
        ActiveModel = ActiveModel,
        Entity = Entity,
        Column = Column,
        Filter = Filter,
    > + UpdateDao<UpdateParams = UpdateParams>
{
}

#[derive(Clone)]
pub struct DefaultNetworkAclRuleDao {
    db: DatabaseConnection,
}

impl DefaultNetworkAclRuleDao {
    pub fn new(db: DatabaseConnection) -> Self {
        Self { db }
    }
}

#[async_trait::async_trait]
impl BaseDao for DefaultNetworkAclRuleDao {
    type Model = Model;
    type ActiveModel = ActiveModel;
    type Entity = Entity;
    type Column = Column;
    type Filter = Filter;

    fn db(&self) -> &DatabaseConnection {
        &self.db
    }
}

#[async_trait::async_trait]
impl UpdateDao for DefaultNetworkAclRuleDao {
    type UpdateParams = UpdateParams;
}

#[async_trait::async_trait]
impl NetworkAclRuleDao for DefaultNetworkAclRuleDao {}
